Imports System
Imports System.Collections.Generic
Imports System.Windows.Controls
Imports System.Windows.Data
Imports System.Windows.Input
Imports System.Windows.Media
Imports System.Windows.Media.Animation
Imports System.Windows.Media.Imaging
Imports System.Windows.Navigation
Imports System.Windows.Shapes
Imports OMANE.Common.UI
Imports ICSharpCode.AvalonEdit.Highlighting
Imports System.CodeDom.Compiler
Imports System.Linq.Expressions
Imports System.Data
Imports OMANE.Modules.Builder.MSFunctions
Imports OMANE.Modules.Builder.MSExpression
Imports ICSharpCode.AvalonEdit.CodeCompletion
Imports System.ComponentModel

Public Class MSExpression
    Public Property FuncStr As String
    Public Property Parameters() As Func(Of String)()
    Public Property IsAggregate As Boolean
    Public Property Sources As MSTable()
    Private _ResultFunctStr As Func(Of String)
    Public ReadOnly Property ResultFunctStr As Func(Of String)
        Get
            Return AddressOf Me.ToString
            '   Return Function() Me.ToString()
        End Get
    End Property

    Public Overrides Function ToString() As String
        Return String.Format(FuncStr, Parameters.Select(Function(f) f.Invoke()).ToArray())
    End Function

#Region "Operators"
    Public Shared Widening Operator CType(ByVal value As Double) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "{0}"
        result.Sources = New MSTable() {}
        Dim strvalue = value.ToString(Globalization.CultureInfo.InvariantCulture)
        result.Parameters = New Func(Of String)() {Function() strvalue}
        Return result
    End Operator
    Public Shared Widening Operator CType(ByVal value As Boolean) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "{0}"
        result.Sources = New MSTable() {}
        Dim strvalue = value.ToString(Globalization.CultureInfo.InvariantCulture)
        result.Parameters = New Func(Of String)() {Function() strvalue}
        Return result
    End Operator
    Public Shared Widening Operator CType(ByVal value As String) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "'{0}'"
        result.Sources = New MSTable() {}
        Dim strvalue = value.ToString(Globalization.CultureInfo.InvariantCulture)
        result.Parameters = New Func(Of String)() {Function() strvalue}
        Return result
    End Operator
    Public Shared Widening Operator CType(ByVal value As Date) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "{0}"
        result.Sources = New MSTable() {}
        Dim strvalue = value.ToString(Globalization.CultureInfo.InvariantCulture)
        result.Parameters = New Func(Of String)() {Function() strvalue}
        Return result
    End Operator
    Public Shared Widening Operator CType(ByVal value As TimeSpan) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "{0}"
        result.Sources = New MSTable() {}
        Dim strvalue = value.ToString("", Globalization.CultureInfo.InvariantCulture)
        result.Parameters = New Func(Of String)() {Function() strvalue}
        Return result
    End Operator
    'Public Shared Widening Operator CType(ByVal value As BaseModelProperty) As MSOExpression
    '    Dim result As New MSOExpression
    '    result.FuncStr = "{0}"
    '    result.Parameters = New Func(Of String)() {value.func}
    '    Return result
    'End Operator

    Public Shared Operator &(ByVal left As MSExpression, ByVal right As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.Sources = Enumerable.Concat(left.Sources, right.Sources).ToArray()
        result.FuncStr = "({0} & {1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr, right.ResultFunctStr}
        Return result
    End Operator

    Public Shared Operator +(ByVal left As MSExpression, ByVal right As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.Sources = Enumerable.Concat(left.Sources, right.Sources).ToArray()
        result.FuncStr = "({0} + {1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr, right.ResultFunctStr}
        Return result
    End Operator
    Public Shared Operator -(ByVal left As MSExpression, ByVal right As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.Sources = Enumerable.Concat(left.Sources, right.Sources).ToArray()
        result.FuncStr = "({0} - {1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr, right.ResultFunctStr}
        Return result
    End Operator
    Public Shared Operator *(ByVal left As MSExpression, ByVal right As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.Sources = Enumerable.Concat(left.Sources, right.Sources).ToArray()
        result.FuncStr = "({0} * {1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr, right.ResultFunctStr}
        Return result
    End Operator
    Public Shared Operator /(ByVal left As MSExpression, ByVal right As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.Sources = Enumerable.Concat(left.Sources, right.Sources).ToArray()
        result.FuncStr = "({0} / {1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr, right.ResultFunctStr}
        Return result
    End Operator

    Public Shared Operator <(ByVal left As MSExpression, ByVal right As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.Sources = Enumerable.Concat(left.Sources, right.Sources).ToArray()
        result.FuncStr = "({0} < {1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr, right.ResultFunctStr}
        Return result
    End Operator
    Public Shared Operator >(ByVal left As MSExpression, ByVal right As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.Sources = Enumerable.Concat(left.Sources, right.Sources).ToArray()
        result.FuncStr = "({0} > {1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr, right.ResultFunctStr}
        Return result
    End Operator
    Public Shared Operator <=(ByVal left As MSExpression, ByVal right As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.Sources = Enumerable.Concat(left.Sources, right.Sources).ToArray()
        result.FuncStr = "({0} <= {1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr, right.ResultFunctStr}
        Return result
    End Operator
    Public Shared Operator >=(ByVal left As MSExpression, ByVal right As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.Sources = Enumerable.Concat(left.Sources, right.Sources).ToArray()
        result.FuncStr = "({0} >= {1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr, right.ResultFunctStr}
        Return result
    End Operator
    Public Shared Operator =(ByVal left As MSExpression, ByVal right As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.Sources = Enumerable.Concat(left.Sources, right.Sources).ToArray()
        result.FuncStr = "({0} = {1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr, right.ResultFunctStr}
        Return result
    End Operator
    Public Shared Operator <>(ByVal left As MSExpression, ByVal right As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.Sources = Enumerable.Concat(left.Sources, right.Sources).ToArray()
        result.FuncStr = "({0} <> {1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr, right.ResultFunctStr}
        Return result
    End Operator

    Public Shared Operator Or(ByVal left As MSExpression, ByVal right As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "({0} OR {1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr, right.ResultFunctStr}
        Return result
    End Operator
    Public Shared Operator And(ByVal left As MSExpression, ByVal right As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "({0} AND {1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr, right.ResultFunctStr}
        Return result
    End Operator
    Public Shared Operator Not(ByVal left As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "(NOT {1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr}
        Return result
    End Operator
    Public Shared Operator Xor(ByVal left As MSExpression, ByVal right As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "({0} XOR {1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr, right.ResultFunctStr}
        Return result
    End Operator

    Public Shared Function Log(ByVal left As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "LOG({0})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr}
        Return result
    End Function
    Public Shared Function Exp(ByVal left As MSExpression, ByVal right As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "EXP({0},{1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr, right.ResultFunctStr}
        Return result
    End Function
    Public Shared Function Pow(ByVal left As MSExpression, ByVal right As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "POW({0},{1})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr, right.ResultFunctStr}
        Return result
    End Function
    Public Shared Function Sqrt(ByVal left As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "SQRT({0})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr}
        Return result
    End Function
    Public Shared Function Abs(ByVal left As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "ABS({0})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr}
        Return result
    End Function

    Public Shared Function Year(ByVal left As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "YEAR({0})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr}
        Return result
    End Function
    Public Shared Function Month(ByVal left As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "MONTH({0})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr}
        Return result
    End Function
    Public Shared Function Day(ByVal left As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "DAY({0})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr}
        Return result
    End Function
    Public Shared Function WeekDay(ByVal left As MSExpression) As MSExpression
        Dim result As New MSExpression
        result.FuncStr = "WEEKDAY({0})"
        result.Parameters = New Func(Of String)() {left.ResultFunctStr}
        Return result
    End Function


#End Region
End Class

Public Class MSJoinExpression
    Inherits MSExpression

    Public Property Left As IEnumerable(Of MSProperty)
    Public Property Right As IEnumerable(Of MSProperty)
    Public Property IsLeftJoin As Boolean = False

    Sub New()
        Me.FuncStr = "INNER JOIN {0} ON {1} = {2}"

    End Sub
End Class